package io.renren.modules.lucky.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.renren.common.redis.RedisLock;
import io.renren.common.redis.RedisUtils;
import io.renren.common.utils.BaseAesUtil;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.Result;
import io.renren.commons.dynamic.datasource.annotation.DataSource;
import io.renren.modules.lucky.dto.background.*;
import io.renren.modules.lucky.dto.LuckyReportDto;
import io.renren.modules.lucky.entity.*;
import io.renren.modules.lucky.service.*;
import io.renren.modules.security.user.UserDetail;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@Service
@DataSource("lucky")
public class LuckyBaseServiceImpl implements LuckyBaseService {
    private static final Logger logger = org.slf4j.LoggerFactory.getLogger(LuckyBaseServiceImpl.class);

    private static final String LUCKY_REPORT_REDIS_KEY = "lucky:report:";

    private static final String URL = "https://brz.huafei123.com/71bda80c-ca6b-4c07-a3ab-b55bb6a6e2ce/5eu7lmbdtf?";

    private static final String LUCKY_SESSION_ID_PLAT_CODE = "lucky:report:sessionId:";

    private static final String LUCKY_CLICK_KEY = "lucky:report:click:";

    @Value("${file.upload-dir}")
    private String uploadDir;


    @Autowired
    private RedisUtils redisUtil;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private LuckyUserConfigService luckyUserConfigService;

    @Autowired
    private LuckyRecordService luckyRecordService;

    @Autowired
    private LuckyOrderService luckyOrderService;

    @Autowired
    private LuckyMediaConfigService luckyMediaConfigService;

    @Autowired
    private LuckyBillService luckyBillService;


    @Override
    public Result report(LuckyReportDto reportDto) {
        //AES解密
        Result<LuckyUserConfigEntity> result = getConfig(reportDto.getSign(), reportDto.getUnionKey(), reportDto.getTimestamp());
        if (result.getCode() != 0) {
            return result;
        }
        LuckyUserConfigEntity luckyUserConfigEntity = result.getData();
        String platCode = luckyUserConfigEntity.getPlatCode();
        //保存sessionId和平台绑定
        redisUtil.set(LUCKY_SESSION_ID_PLAT_CODE + reportDto.getSessionId(), platCode, 86400);

        // 处理上报埋点 先存redis 定时任务存表

        //yyyy-MM-dd
        String dateStr = DateUtils.format(new Date());

        String keyStr = reportDto.getPhone() + platCode + reportDto.getSessionId();

        String lockKey = LUCKY_REPORT_REDIS_KEY + "lock:" + keyStr;
        String requestId = UUID.fastUUID().toString();
        try {
            if (redisLock.tryLock(lockKey, requestId)) {
                // 检查是否已有记录
                String redisKey = LUCKY_REPORT_REDIS_KEY + dateStr + ":" + platCode;
                String tempKey = platCode + reportDto.getSessionId() + reportDto.getIp();
                Object existingData = redisUtil.hGet(redisKey, tempKey);
                if (ObjectUtil.isNotEmpty(existingData)) {
                    return new Result().error("重复埋点请求");
                }

                //添加记录
                Map<String, Object> map = Maps.newHashMap();
                map.put("platCode", platCode);
                map.put("ip", reportDto.getIp());
                map.put("unionKey", reportDto.getUnionKey());
                map.put("sessionId", reportDto.getSessionId());

                if (StrUtil.isNotBlank(reportDto.getPhone())) {
                    map.put("phone", reportDto.getPhone());
                }
                if (StrUtil.isNotBlank(reportDto.getIsp())) {
                    map.put("isp", reportDto.getIsp());
                }
                if (StrUtil.isNotBlank(reportDto.getProvince())) {
                    map.put("province", reportDto.getProvince());
                    map.put("city", reportDto.getCity());
                    map.put("district", reportDto.getDistrict());
                }

                map.put("pointNum", reportDto.getPointNum());

                if (StrUtil.isNotBlank(reportDto.getCurrentUrl())) {
                    map.put("curUrl", reportDto.getCurrentUrl());
                }
                if (StrUtil.isNotBlank(reportDto.getRefererUrl())) {
                    map.put("preUrl", reportDto.getRefererUrl());
                }

                if (StrUtil.isNotBlank(reportDto.getMediaId())) {
                    map.put("mediaId", reportDto.getMediaId());
                }
                if (StrUtil.isNotBlank(reportDto.getErrCode())) {
                    map.put("errCode", reportDto.getErrCode());
                }
                if (StrUtil.isNotBlank(reportDto.getErrMsg())) {
                    map.put("errMsg", reportDto.getErrMsg());
                }
                //重府校验
                map.put(tempKey, 1);
                //时间
                map.put("createTime", new Date());
                redisUtil.hSet(redisKey, reportDto.getSessionId(), map, 259200);
            } else {
                return new Result().error("系统繁忙，稍后再试");
            }
        } finally {
            redisLock.unlock(lockKey, requestId);
            logger.info("存储埋点成功，释放锁成功");
        }
        Map<String, String> params = Maps.newHashMap();
        String phone = reportDto.getPhone();
        String sessionId = reportDto.getSessionId();
        params.put("sessionId", sessionId);
        String province = reportDto.getProvince();
        if (StrUtil.isNotBlank(province)) {
            params.put("province", province);
        }
        if (StrUtil.isNotBlank(phone)) {
            params.put("phone", phone);
        }
        String paramStr = URLUtil.buildQuery(params, Charset.defaultCharset());

        return new Result().ok(URL + paramStr);
    }

    /**
     * 点击上报
     */
    @Override
    public Result click(LuckyClickReq clickReq) {
        //获取商户code 通过unionKey
        /*Result<LuckyUserConfigEntity> result = getConfig(clickReq.getUnionKey(), clickReq.getUnionKey(), clickReq.getTimestamp());
        if (result.getCode() != 0) {
            return result;
        }*/
        String platCode = redisUtil.get(LUCKY_SESSION_ID_PLAT_CODE + clickReq.getSessionId()).toString();

        //yyyy-MM-dd
        String dateStr = DateUtils.format(new Date());
        String redisKey = LUCKY_REPORT_REDIS_KEY + dateStr + ":" + platCode;

        Object existingData = redisUtil.hGet(redisKey, clickReq.getSessionId());
        if (ObjectUtil.isNotEmpty(existingData)) {
            Map<String, Object> existingMap = (Map<String, Object>) existingData;
            // 添加新的 key-value
            existingMap.put("isClick", 1);
            // 更新 redis 中的数据
            redisUtil.hSet(redisKey, clickReq.getSessionId(), existingMap);
        }
        return new Result().ok("success");
    }

    /**
     * 订单成功上报
     */
    @Override
    public Result order(LuckyCallBackReq callBackReq) {
        //获取商户code 通过unionKey
        //获取商户code 通过unionKey
        Object object = redisUtil.get(LUCKY_SESSION_ID_PLAT_CODE + callBackReq.getSessionId());
        LuckyRecordEntity entity = null;
        String platCode;
        if (ObjectUtil.isEmpty(object)) {
            //查询表
            entity = luckyRecordService.queryBySessionId(callBackReq.getSessionId());
            platCode = entity.getPlatCode();
        } else {
            platCode = object.toString();
        }

        //yyyy-MM-dd
        String dateStr = DateUtils.format(new Date());
        String redisKey = LUCKY_REPORT_REDIS_KEY + dateStr + ":" + platCode;


        Object existingData = redisUtil.hGet(redisKey, callBackReq.getSessionId());
        if (ObjectUtil.isNotEmpty(existingData)) {
            logger.info("订单上报，redisKey:{},sessionId:{}", redisKey, callBackReq.getSessionId());
            Map<String, Object> existingMap = (Map<String, Object>) existingData;
            //将businessId存到List中 方便查询
            Object listObject = existingMap.get("businessIdList");
            Set<String> businessIdSet;
            if (ObjectUtil.isEmpty(listObject)) {
                businessIdSet = Sets.newHashSet();
                businessIdSet.add(callBackReq.getBusinessId());
            } else {
                businessIdSet = (Set<String>) listObject;
                businessIdSet.add(callBackReq.getBusinessId());
            }
            existingMap.put("businessIdList", businessIdSet);

            // 获取现有的 businessId ，以businessId存储
            Object o = existingMap.get(callBackReq.getBusinessId());
            if (ObjectUtil.isEmpty(o)) {
                List<LuckyCallBackReq> businessList = Lists.newArrayList();
                businessList.add(callBackReq);
                existingMap.put(callBackReq.getBusinessId(), JSON.toJSONString(businessList));

                // 更新 redis 中的数据
                redisUtil.hSet(redisKey, callBackReq.getSessionId(), existingMap);
                return new Result().ok("success");
            }
            return new Result().error("重复记录");
        } else {
            if (entity == null) {
                //再查下
                entity = luckyRecordService.queryBySessionId(callBackReq.getSessionId());
            }
            //直接存表
            if (ObjectUtil.isNotEmpty(entity)) {
                //查询下是否已经有了
                LuckyOrderEntity luckyOrder = luckyOrderService.queryByParam(callBackReq.getSessionId(), callBackReq.getBusinessId(), platCode);
                if (ObjectUtil.isNotEmpty(luckyOrder)) {
                    return new Result().error("重复记录");

                }
                LuckyOrderEntity orderEntity = new LuckyOrderEntity();
                orderEntity.setSessionId(callBackReq.getSessionId());
                orderEntity.setPlatCode(platCode);
                orderEntity.setPhone(entity.getPhone());
                orderEntity.setIp(entity.getIp());
                orderEntity.setBusinessId(callBackReq.getBusinessId());
                orderEntity.setBusinessName(callBackReq.getBusinessName());
                orderEntity.setBusinessAmount(new BigDecimal(callBackReq.getBusinessAmount()));
                orderEntity.setOrderTime(callBackReq.getOrderTime());
                orderEntity.setMediaId(entity.getMediaId());
                orderEntity.setProvince(entity.getProvince());
                orderEntity.setCity(entity.getCity());
                orderEntity.setIsp(entity.getIsp());
                /*boolean flag = luckyOrderService.insert(orderEntity);
                if (!flag) {
                    return new Result().error("系统繁忙，请稍后再试");
                }*/
            }
            return new Result().ok("success");
        }
    }

    /**
     * 收益报表查询
     */
    @Override
    public Result reportQuery(ReportReqDto reportReq, UserDetail user) {
        //获取用户ID查询租户配置
        LuckyUserConfigEntity luckyUserConfigEntity = luckyUserConfigService.getEntityByUid(user.getId());
        if (ObjectUtil.isEmpty(luckyUserConfigEntity)) {
            return new Result().error("未配置商户信息");
        }

        // 根据商户code查询表中数据
        String platCode = luckyUserConfigEntity.getPlatCode();
        reportReq.setPlatCode(platCode);
        ReportRespDto respDto;
        try {
            List<LuckyRecordEntity> entityList = luckyRecordService.queryListByParam(reportReq, platCode);

            respDto = new ReportRespDto();
            List<ReportRespDto.Data> dataList = Lists.newArrayList();

            //曝光合计
            int uvSum = 0;
            //点击合计
            int clicksSum = 0;
            //预计收益合计
            BigDecimal forecastRevenueSum = BigDecimal.ZERO;
            //点击率合计
            int clickRateSum = 0;
            //点击收益率合计
            int clickRevenueRateSum = 0;

            for (LuckyRecordEntity entity : entityList) {
                ReportRespDto.Data data = new ReportRespDto.Data();
                //放入查询的数据
                data.setPlatCode(entity.getPlatCode());
                data.setProvince(entity.getProvince());

                String mediaId = entity.getMediaId();
                data.setMediaName("默认");
                if (StrUtil.isNotBlank(mediaId)) {
                    data.setMediaId(mediaId);
                    LuckyMediaConfigEntity mediaConfigEntity = luckyMediaConfigService.getByMediaId(mediaId);

                    if (ObjectUtil.isNotNull(mediaConfigEntity)) {
                        data.setMediaName(mediaConfigEntity.getMediaName());
                    }
                } else {
                    data.setMediaId(mediaId);
                }

                data.setDateStr(entity.getFormattedCreateTime());
                data.setUv(entity.getUv().toString());
                data.setClicks(entity.getClicks().toString());


                data.setForecastRevenue(entity.getForecastRevenue().toString());
                // 计算点击率和点击收益率
                if (entity.getUv() != null && entity.getUv() > 0) {
                    data.setClickRate(String.format("%.2f%%", (entity.getClicks() * 100.0 / entity.getUv())));
                }

                //点击收益率（预计收益/点击量）
                if (entity.getClicks() != null && entity.getClicks() > 0) {
                    data.setClickRevenueRate(String.format("%.2f", (entity.getForecastRevenue().doubleValue() / entity.getClicks())));
                }
                //千层曝光收益（预计收益/曝光UV*1000）
                if (entity.getUv() != null && entity.getUv() > 0) {
                    data.setThousandExposureRevenue(String.format("%.2f", (entity.getForecastRevenue().doubleValue() / entity.getUv() * 1000)));
                }

                // 累加汇总数据
                if (entity.getUv() != null) {
                    uvSum += entity.getUv();
                }
                if (entity.getClicks() != null) {
                    clicksSum += entity.getClicks();
                }
                if (entity.getForecastRevenue() != null) {
                    forecastRevenueSum = forecastRevenueSum.add(entity.getForecastRevenue());
                }
                dataList.add(data);
            }
            respDto.setDataList(dataList);

            clickRateSum = uvSum > 0 ? (int) (clicksSum * 100.0 / uvSum) : 0;
            clickRevenueRateSum = clicksSum > 0 ? (int) (forecastRevenueSum.doubleValue() / clicksSum) : 0;
            respDto.setUvSum(String.valueOf(uvSum));
            respDto.setClicksSum(String.valueOf(clicksSum));
            respDto.setForecastRevenueSum(forecastRevenueSum.toString());
            respDto.setClickRateSum(String.valueOf(clickRateSum));
            respDto.setClickRevenueRateSum(String.valueOf(clickRevenueRateSum));
        } catch (Exception e) {
            logger.error("收益报表查询异常", e);
            return new Result().error("系统繁忙，请稍后再试");
        }

        return new Result().ok(respDto);
    }

    /**
     * 主页数据
     */
    @Override
    public Result index(LuckyIndexReq indexReq, UserDetail user) {
        //获取用户ID查询租户配置
        LuckyUserConfigEntity luckyUserConfigEntity = luckyUserConfigService.getEntityByUid(user.getId());
        if (ObjectUtil.isEmpty(luckyUserConfigEntity)) {
            return new Result().error("未配置商户信息");
        }
        LuckyIndexResp resp = new LuckyIndexResp();
        String platCode = luckyUserConfigEntity.getPlatCode();
        //查询昨日数据
        LuckyIndexResp yesterdayData = luckyRecordService.queryYesterdayData(platCode, indexReq);
        if (ObjectUtil.isNotEmpty(yesterdayData)) {
            resp.setYesterdayClick(yesterdayData.getYesterdayClick());
            resp.setYesterdayClick(yesterdayData.getYesterdayClick());
            resp.setYesterdayExposure(yesterdayData.getYesterdayExposure());
        }

        //查询前七日数据
        LuckyIndexResp sevenDaysData = luckyRecordService.querySevenDaysData(platCode, indexReq);
        if (ObjectUtil.isNotEmpty(sevenDaysData)) {
            resp.setSevenDaysIncome(sevenDaysData.getSevenDaysIncome());
            resp.setSevenDaysClick(sevenDaysData.getSevenDaysClick());
            resp.setSevenDaysExposure(sevenDaysData.getSevenDaysExposure());
        }

        //查询本月数据
        LuckyIndexResp monthData = luckyRecordService.queryMonthData(platCode, indexReq);
        if (ObjectUtil.isNotEmpty(monthData)) {
            resp.setMonthIncome(monthData.getMonthIncome());
            resp.setMonthClick(monthData.getMonthClick());
            resp.setMonthExposure(monthData.getMonthExposure());
        }
        // 结算中金额
        BigDecimal settlementAmount = luckyBillService.querySettlementAmount(platCode);
        // 已结算金额
        BigDecimal paidAmount = luckyBillService.queryPaidAmount(platCode);

        resp.setSettlementAmount(settlementAmount.toString());
        resp.setTotalIncome(paidAmount.toString());
        return new Result().ok(resp);
    }

    /**
     * 主页报表数据
     */
    @Override
    public Result indexCharts(LuckyIndexReq indexReq, UserDetail user) {//获取用户ID查询租户配置
        LuckyUserConfigEntity luckyUserConfigEntity = luckyUserConfigService.getEntityByUid(user.getId());
        if (ObjectUtil.isEmpty(luckyUserConfigEntity)) {
            return new Result().error("未配置商户信息");
        }
        LuckyIndexChartsResp resp = new LuckyIndexChartsResp();
        String platCode = luckyUserConfigEntity.getPlatCode();
        //查询图表数据
        List<LuckyIndexChartsResp> chartsData = luckyRecordService.queryChartsData(platCode, indexReq);
        return new Result().ok(chartsData);
    }

    /**
     * 上传文件
     *
     * @param file
     * @param user
     * @return
     */
    @Override
    public String uploadFile(MultipartFile file, UserDetail user) {
        try {
            String fileName = StringUtils.cleanPath(file.getOriginalFilename());
            //查询租户配置
            String platCode = luckyUserConfigService.getEntityByUid(user.getId()).getPlatCode();
            String dateStr = DateUtils.format(new Date(), DateUtils.DATE_PATTERN_1);
            String newName = dateStr + "-" + fileName;

            Path dirPath = Paths.get(uploadDir + File.separator + platCode);
            if (!Files.exists(dirPath)) {
                Files.createDirectories(dirPath);
            }
            Path path = Paths.get(dirPath + File.separator + newName);
            if (Files.exists(path)) {
                Files.delete(path);
            }
            Files.copy(file.getInputStream(), path);

            //String downloadUrl = "/api/base/download/" + fileName;
            logger.info("File uploaded successfully. Download URL: {}", newName);
            return newName;
        } catch (IOException e) {
            logger.error("Failed to upload file", e);
            return "Failed to upload file";
        } finally {
            try {
                file.getInputStream().close();
            } catch (IOException e) {
                logger.error("Failed to close input stream", e);
            }
        }

    }

    @Override
    public byte[] downloadFile(String fileName, UserDetail user) {
        try {
            //查询租户配置
            String platCode = luckyUserConfigService.getEntityByUid(user.getId()).getPlatCode();
            String pathStr = uploadDir + File.separator + platCode + File.separator + fileName;
            Path path = Paths.get(pathStr);
            byte[] fileBytes = Files.readAllBytes(path);
            return fileBytes;
        } catch (IOException e) {
            return null;
        }
    }

    private Result<LuckyUserConfigEntity> getConfig(String sign, String unionKeyStr, String timestamp) {
        // AESUtil.decrypt()
        //获取商户code 通过unionKey
        LuckyUserConfigEntity luckyUserConfigEntity = luckyUserConfigService.getEntityByUnionKey(unionKeyStr);
        if (ObjectUtil.isEmpty(luckyUserConfigEntity)) {
            return new Result<LuckyUserConfigEntity>().error("配置信息不存在");
        }

        String decryptStr = BaseAesUtil.aesDecrypt(sign, luckyUserConfigEntity.getAesKey());
        if (StrUtil.isBlank(decryptStr) || !StrUtil.equals(decryptStr, (unionKeyStr + timestamp))) {
            return new Result<LuckyUserConfigEntity>().error("加密数据不正确");
        }

        return new Result<LuckyUserConfigEntity>().ok(luckyUserConfigEntity);
    }
}
